/* StaticRowsTV.m:
 * You may freely copy, distribute, and reuse the code in this example.
 * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
 * fitness for any particular use.
 *
 * Written by: Mai Nguyen, NeXT Developer Support
 *
 */
#import "StaticRowsTV.h"

#define INSTALL_MODEL NXLocalizedString("Please install SybaseDemo.dbmodela or OracleDemo.dbmodela in your project.", NULL, "Notify user that the ascii model files must be installed in his project directory.")

/* Comment this line out if you want to run an Oracle version */
/* #define	SYBASE_DEMO	 1*/

@implementation StaticRowsTV
/*
* Miscellaneous initialization tasks: connect to database, initialize
* tableview, set up dbModule. 
*/ 
-appDidInit:sender
{
	NXRect viewFrame;
	
#ifdef SYBASE_DEMO	
	/* Notify the user if the database can't be found */
	if (!(dbDatabase = [DBDatabase findDatabaseNamed:"SybaseDemo" 
					connect:YES])) {
		NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
		return self;
	}
#else
	/* Notify the user if the database can't be found */
	if (!(dbDatabase = [DBDatabase findDatabaseNamed:"OracleDemo" 
					connect:YES])) {
		NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
		return self;
	}
#endif
 
	[dbDatabase setDelegate:self];
	
		/* Install the tableview into the custom view */
	[[dbTableView getFrame:&viewFrame] free];
	dbTableView = [[DBTableView alloc] initFrame:&viewFrame];
	[[window contentView] addSubview:dbTableView];
	[dbTableView setRowHeadingVisible:YES];
	[dbTableView setColumnHeadingVisible:NO];
	[dbTableView setEditable:YES];
	[dbTableView setHorizScrollerRequired:YES];
	[dbTableView setVertScrollerRequired:YES];
	[dbTableView setDelegate: self];

#ifdef SYBASE_DEMO
	rootEntity = [dbDatabase entityNamed:"Author"];
#else
	rootEntity = [dbDatabase entityNamed:"Employee"];
#endif
		/* Must initialize your dbModule */
  	dbModule = [[DBModule alloc] initDatabase:dbDatabase 
							entity:rootEntity];					
	dbFetchGroup = [dbModule rootFetchGroup];
	[dbFetchGroup setDelegate:self];
 	[window disableFlushWindow];
	[self initTableView];

			/* Initialize the retrieval order to be ascending order
			 */
#ifdef SYBASE_DEMO
	sortProp = [[dbModule entity] propertyNamed:"lastName"];
#else
	sortProp = [[dbModule entity] propertyNamed:"EmployeeName"];
#endif
			
	[[dbFetchGroup recordList] addRetrieveOrder:DB_AscendingOrder for:sortProp];
		

	[dbFetchGroup fetchContentsOf:nil usingQualifier:nil];	 
	[dbTableView display];

	[[window reenableFlushWindow] flushWindow];
	
	return self;
}
 

/* In order to replicate the Interface Builder functionality, one has to
 * add an expression to the fetchgroup for each table property.
 */

- addTableRow:(const char *)label
{
    id newExpression;

    /* allocate a new expression, add it to the FetchGroup and add it */
	/* to the TableView */
	newExpression = [[DBExpression alloc] initForEntity:[dbModule entity]
				fromDescription:label];
	[dbFetchGroup addExpression:newExpression];
	[dbTableView  addRow:newExpression withTitle:label];
    return self;
}

- initTableView
{
	int i, propCount;
	id prop;

  	propList = [[List alloc] init];

	/* Just pick the most important properties for this example */
#ifdef SYBASE_DEMO
	[propList addObject: [rootEntity propertyNamed:"lastName"]];
	[propList addObject: [rootEntity propertyNamed:"firstName"]];
	[propList addObject: [rootEntity propertyNamed:"city"]];
	[propList addObject: [rootEntity propertyNamed:"phone"]];
#else
	[propList addObject: [rootEntity propertyNamed:"EmployeeName"]];
	[propList addObject: [rootEntity propertyNamed:"job"]];
	[propList addObject: [rootEntity propertyNamed:"salary"]];
	[propList addObject: [rootEntity propertyNamed:"hiredate"]];
#endif	
	 
    propCount = [propList count];

    for (i = 0; i < propCount; i++) {
	    prop = [propList objectAt:i];
		[self addTableRow:[prop name]];
		[[dbTableView rowAt:i] setMinSize:30.0];
		} 	

		/* Make the StaticRowsTV object
		 * become the tableview data source.
		 */
	[dbTableView setDataSource:self];

		/*
		 * free property list which is no longer needed
		 */

	[propList free];
	[window makeKeyAndOrderFront:self];
    return self;
}

- showAll:sender
{
	[dbModule fetchAllRecords:sender];
		/* These methods force the tableview to update the display */
	[dbFetchGroup redisplayEverything];
	[dbTableView display];
	return self;
}

- save:sender
{
	/* This method is needed to force a save. Otherwise, a Carriage Return
	 * is needed before the save actually happens.
	 * The typecasting is needed to avoid compiler warnings.
     */
	 [(DBTableView *)dbTableView endEditing];

	[dbModule saveChanges:sender];
	return self;
}

- free
{
	if (dbTableView)
		[dbTableView free];
	return [super free];
}

/* DBDatabase delegate methods to log SQL queries  - Useful for debugging */

- (BOOL)db:aDb willEvaluateString:(const char*)aString usingBinder:aBinder
{
	fprintf(stderr, "SQL query:%s\n", aString);
	return YES;
}

/******************* DBFetchGroup delegate methods ******************/

/*
 * This method is called at each SELECT operation. 
 * Restore the proper sort order.
 */
- fetchGroupWillFetch:fetchGroup
{			
	[[dbFetchGroup recordList] addRetrieveOrder:DB_AscendingOrder for:sortProp];
	return self;
}
 

/*****************  DBTableView dataSource methods  *****************/
 
- (unsigned)columnCount
{
    return [[dbFetchGroup recordList] count];
}


- getValueFor:aProperty at:(unsigned)index into:(DBValue*)aValue
{
 	return [[dbFetchGroup recordList] getValue:aValue forProperty:aProperty at:index];
}

- setValueFor:aProperty at:(unsigned)index from:(DBValue*)aValue
{
     
    [[dbFetchGroup recordList] setValue:aValue forProperty:aProperty at:index];
    return self;
}

@end
